#include "calculator.h"
#include <cmath>
#include <stdexcept>
#include <iostream>
#include <cctype>

Calculator::Calculator() : pos(0) {}

// 跳过空白字符
void Calculator::skipWhitespace() {
    while (pos < expression.length() && isspace(expression[pos])) {
        pos++;
    }
}

// 检查是否为操作符
bool Calculator::isOperator(char c) { return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%'; }

// 检查是否为函数名
bool Calculator::isFunction(const std::string &name) {
    return name == "sin" || name == "cos" || name == "tan" || name == "asin" || name == "acos" || name == "atan" ||
           name == "sinh" || name == "cosh" || name == "tanh" || name == "ln" || name == "log" || name == "sqrt" ||
           name == "exp" || name == "abs" || name == "floor" || name == "ceil";
}

// 解析阶乘操作
double Calculator::parseFactorial() {
    double result = parseFunction();

    skipWhitespace();
    // 检查是否有阶乘操作符
    while (pos < expression.length() && expression[pos] == '!') {
        pos++; // 跳过 '!' 符号
        int n = static_cast<int>(result);
        if (n != result || n < 0) {
            throw std::runtime_error("Factorial operand must be a non-negative integer");
        }
        result = factorial(n);
        skipWhitespace();
    }

    return result;
}

// 解析角度转换
double Calculator::parseAngleConversion() {
    double result = parseFactorial();

    skipWhitespace();
    // 检查是否有角度转换标识
    if (pos + 1 < expression.length() && expression[pos] == 'd' && expression[pos + 1] == 'r') {
        // 度转弧度: dr后缀
        pos += 2;
        result = degToRad(result);
    } else if (pos + 1 < expression.length() && expression[pos] == 'r' && expression[pos + 1] == 'd') {
        // 弧度转度: rd后缀
        pos += 2;
        result = radToDeg(result);
    }

    return result;
}

// 解析数字
double Calculator::parseNumber() {
    skipWhitespace();

    if (pos >= expression.length()) {
        throw std::runtime_error("Unexpected end of expression");
    }

    // 处理负号
    bool negative = false;
    if (expression[pos] == '-') {
        negative = true;
        pos++;
    } else if (expression[pos] == '+') {
        pos++;
    }

    // 解析数字
    double result = 0;
    bool hasDecimal = false;
    double decimalPlace = 0.1;

    while (pos < expression.length() && (isdigit(expression[pos]) || expression[pos] == '.')) {
        if (expression[pos] == '.') {
            if (hasDecimal) {
                throw std::runtime_error("Invalid number format");
            }
            hasDecimal = true;
        } else {
            if (!hasDecimal) {
                result = result * 10 + (expression[pos] - '0');
            } else {
                result += (expression[pos] - '0') * decimalPlace;
                decimalPlace *= 0.1;
            }
        }
        pos++;
    }

    if (negative) {
        result = -result;
    }

    return result;
}

// 解析函数
double Calculator::parseFunction() {
    skipWhitespace();

    if (pos >= expression.length()) {
        throw std::runtime_error("Unexpected end of expression");
    }

    // 检查是否为函数
    size_t startPos = pos;
    while (pos < expression.length() && isalpha(expression[pos])) {
        pos++;
    }

    std::string funcName = expression.substr(startPos, pos - startPos);

    if (!isFunction(funcName)) {
        pos = startPos; // 回退
        return parseFactor();
    }

    skipWhitespace();

    if (pos >= expression.length() || expression[pos] != '(') {
        throw std::runtime_error("Expected '(' after function name");
    }

    pos++; // 跳过 '('
    double arg = parseExpression();

    skipWhitespace();

    if (pos >= expression.length() || expression[pos] != ')') {
        throw std::runtime_error("Expected ')' after function argument");
    }

    pos++; // 跳过 ')'

    // 计算函数值
    double result;
    if (funcName == "sin")
        result = functionSin(arg);
    else if (funcName == "cos")
        result = functionCos(arg);
    else if (funcName == "tan")
        result = functionTan(arg);
    else if (funcName == "asin")
        result = functionAsin(arg);
    else if (funcName == "acos")
        result = functionAcos(arg);
    else if (funcName == "atan")
        result = functionAtan(arg);
    else if (funcName == "sinh")
        result = functionSinh(arg);
    else if (funcName == "cosh")
        result = functionCosh(arg);
    else if (funcName == "tanh")
        result = functionTanh(arg);
    else if (funcName == "ln")
        result = functionLn(arg);
    else if (funcName == "log")
        result = functionLog10(arg);
    else if (funcName == "sqrt")
        result = functionSqrt(arg);
    else if (funcName == "exp")
        result = functionExp(arg);
    else if (funcName == "abs")
        result = functionAbs(arg);
    else if (funcName == "floor")
        result = functionFloor(arg);
    else if (funcName == "ceil")
        result = functionCeil(arg);
    else
        throw std::runtime_error("Unknown function: " + funcName);

    // 对函数结果支持阶乘和角度转换
    skipWhitespace();
    // 处理函数结果后的阶乘
    while (pos < expression.length() && expression[pos] == '!') {
        pos++;
        int n = static_cast<int>(result);
        if (n != result || n < 0) {
            throw std::runtime_error("Factorial operand must be a non-negative integer");
        }
        result = factorial(n);
        skipWhitespace();
    }

    // 处理函数结果后的角度转换
    if (pos + 1 < expression.length() && expression[pos] == 'd' && expression[pos + 1] == 'r') {
        pos += 2;
        result = degToRad(result);
    } else if (pos + 1 < expression.length() && expression[pos] == 'r' && expression[pos + 1] == 'd') {
        pos += 2;
        result = radToDeg(result);
    }

    return result;
}


// 解析因子
double Calculator::parseFactor() {
    skipWhitespace();

    if (pos >= expression.length()) {
        throw std::runtime_error("Unexpected end of expression");
    }

    // 处理括号
    if (expression[pos] == '(') {
        pos++;
        double result = parseExpression();
        skipWhitespace();
        if (pos >= expression.length() || expression[pos] != ')') {
            throw std::runtime_error("Expected ')'");
        }
        pos++;

        // 检查括号后的阶乘和角度转换
        skipWhitespace();
        // 处理括号后的阶乘
        while (pos < expression.length() && expression[pos] == '!') {
            pos++;
            int n = static_cast<int>(result);
            if (n != result || n < 0) {
                throw std::runtime_error("Factorial operand must be a non-negative integer");
            }
            result = factorial(n);
            skipWhitespace();
        }

        // 处理括号后的角度转换
        if (pos + 1 < expression.length() && expression[pos] == 'd' && expression[pos + 1] == 'r') {
            pos += 2;
            result = degToRad(result);
        } else if (pos + 1 < expression.length() && expression[pos] == 'r' && expression[pos + 1] == 'd') {
            pos += 2;
            result = radToDeg(result);
        }

        return result;
    }

    // 处理数字 - 直接调用parseNumber()函数
    if (isdigit(expression[pos]) || expression[pos] == '.' || expression[pos] == '-' || expression[pos] == '+') {
        double result = parseNumber(); // 直接调用parseNumber()
        // 对数字结果支持阶乘和角度转换
        skipWhitespace();
        // 处理数字后的阶乘
        while (pos < expression.length() && expression[pos] == '!') {
            pos++;
            int n = static_cast<int>(result);
            if (n != result || n < 0) {
                throw std::runtime_error("Factorial operand must be a non-negative integer");
            }
            result = factorial(n);
            skipWhitespace();
        }

        // 处理数字后的角度转换
        if (pos + 1 < expression.length() && expression[pos] == 'd' && expression[pos + 1] == 'r') {
            pos += 2;
            result = degToRad(result);
        } else if (pos + 1 < expression.length() && expression[pos] == 'r' && expression[pos + 1] == 'd') {
            pos += 2;
            result = radToDeg(result);
        }

        return result;
    }

    // 处理函数
    if (isalpha(expression[pos])) {
        return parseAngleConversion();
    }

    // 检查是否为操作符
    if (isOperator(expression[pos])) {
        throw std::runtime_error("Unexpected operator: " + std::string(1, expression[pos]));
    }

    throw std::runtime_error("Unexpected character: " + std::string(1, expression[pos]));
}

// 解析项
double Calculator::parseTerm() {
    double result = parseFactor();

    while (pos < expression.length()) {
        skipWhitespace();
        if (pos >= expression.length())
            break;

        char op = expression[pos];
        // 使用isOperator检查是否为操作符
        if (isOperator(op) && (op == '*' || op == '/')) {
            pos++;
            double rhs = parseFactor();
            if (op == '*') {
                result *= rhs;
            } else {
                if (rhs == 0) {
                    throw std::runtime_error("Division by zero");
                }
                result /= rhs;
            }
        } else if (op == '%') {
            pos++;
            double rhs = parseFactor();
            if (rhs == 0) {
                throw std::runtime_error("Modulo by zero");
            }
            result = fmod(result, rhs);
        } else {
            // 如果不是有效的操作符，则退出循环
            break;
        }
    }

    return result;
}

// 解析表达式
double Calculator::parseExpression() {
    double result = parseTerm();

    while (pos < expression.length()) {
        skipWhitespace();
        if (pos >= expression.length())
            break;

        char op = expression[pos];
        // 使用isOperator检查是否为操作符
        if (isOperator(op) && (op == '+' || op == '-')) {
            pos++;
            double rhs = parseTerm();
            if (op == '+') {
                result += rhs;
            } else {
                result -= rhs;
            }
        } else if (isOperator(op) && op == '^') {
            pos++;
            double rhs = parseTerm();
            result = pow(result, rhs);
        } else {
            // 如果不是有效的操作符，则退出循环
            break;
        }
    }

    return result;
}

// 计算表达式
double Calculator::evaluate(const std::string &expr) {
    expression = expr;
    pos = 0;
    return parseExpression();
}

// 复数运算实现
Complex Calculator::complexAdd(const Complex &a, const Complex &b) { return a + b; }

Complex Calculator::complexSubtract(const Complex &a, const Complex &b) { return a - b; }

Complex Calculator::complexMultiply(const Complex &a, const Complex &b) { return a * b; }

Complex Calculator::complexDivide(const Complex &a, const Complex &b) {
    if (b == Complex(0, 0)) {
        throw std::runtime_error("Complex division by zero");
    }
    return a / b;
}

Complex Calculator::complexPower(const Complex &base, const Complex &exp) { return std::pow(base, exp); }

Complex Calculator::complexSqrt(const Complex &z) { return std::sqrt(z); }

Complex Calculator::complexSin(const Complex &z) { return std::sin(z); }

Complex Calculator::complexCos(const Complex &z) { return std::cos(z); }

Complex Calculator::complexTan(const Complex &z) { return std::tan(z); }

Complex Calculator::complexExp(const Complex &z) { return std::exp(z); }

Complex Calculator::complexLog(const Complex &z) {
    if (z == Complex(0, 0)) {
        throw std::runtime_error("Logarithm of zero");
    }
    return std::log(z);
}

// 微积分实现
double Calculator::numericalDerivative(const std::function<double(double)> &f, double x, double h) {
    return (f(x + h) - f(x - h)) / (2 * h);
}

double Calculator::numericalIntegral(const std::function<double(double)> &f, double a, double b, int n) {
    double h = (b - a) / n;
    double sum = (f(a) + f(b)) / 2.0;

    for (int i = 1; i < n; i++) {
        sum += f(a + i * h);
    }

    return sum * h;
}

double Calculator::derivative(const std::function<double(double)> &f, double x) { return numericalDerivative(f, x); }

double Calculator::integral(const std::function<double(double)> &f, double a, double b) {
    return numericalIntegral(f, a, b);
}

// 预定义函数实现
double Calculator::functionSin(double x) { return sin(x); }

double Calculator::functionCos(double x) { return cos(x); }

double Calculator::functionTan(double x) { return tan(x); }

double Calculator::functionAsin(double x) {
    if (x < -1 || x > 1) {
        throw std::runtime_error("asin domain error");
    }
    return asin(x);
}

double Calculator::functionAcos(double x) {
    if (x < -1 || x > 1) {
        throw std::runtime_error("acos domain error");
    }
    return acos(x);
}

double Calculator::functionAtan(double x) { return atan(x); }

double Calculator::functionSinh(double x) { return sinh(x); }

double Calculator::functionCosh(double x) { return cosh(x); }

double Calculator::functionTanh(double x) { return tanh(x); }

double Calculator::functionLn(double x) {
    if (x <= 0) {
        throw std::runtime_error("ln domain error");
    }
    return log(x);
}

double Calculator::functionLog10(double x) {
    if (x <= 0) {
        throw std::runtime_error("log domain error");
    }
    return log10(x);
}

double Calculator::functionSqrt(double x) {
    if (x < 0) {
        throw std::runtime_error("sqrt domain error");
    }
    return sqrt(x);
}

double Calculator::functionExp(double x) { return exp(x); }

double Calculator::functionAbs(double x) { return fabs(x); }

double Calculator::functionFloor(double x) { return floor(x); }

double Calculator::functionCeil(double x) { return ceil(x); }

double Calculator::factorial(int n) {
    if (n < 0) {
        throw std::runtime_error("Factorial of negative number");
    }
    if (n > 170) {
        throw std::runtime_error("Factorial result too large");
    }

    double result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
}

double Calculator::degToRad(double deg) { return deg * M_PI / 180.0; }

double Calculator::radToDeg(double rad) { return rad * 180.0 / M_PI; }
